'''
mess shangweiji

connect: sqlserver (get set) , plcS7 (get)

'''
import threading
import time
import traceback

from sql_server.HuoniMessClient import HuoniMessClient
from plc_S7.HuoniPlcScanClient import HuoniPlcScanClientBase, config as plc_config
from printer.HoneyPrintClient import HoneyPrintClient

from concurrent.futures import ThreadPoolExecutor
import queue
from log import logger
print = logger.info

class BoundThreadPoolExecutor(ThreadPoolExecutor):
    #对ThreadPoolExecutor 进行重写，给队列设置边界
    def __init__(self, qsize: int = None, *args, **kwargs):
        super(BoundThreadPoolExecutor, self).__init__(*args, **kwargs)
        self._work_queue = queue.Queue(qsize)


main_config = { # pn: plc_address
    'CBL-500-120-S00-05': plc_config.PlaceCable, # shu ju xian p3
    # 'CT47-X1N-37D1E0G': plc_config.PlacePhone, # p7
    # 'CT47-X1N-38D1E0G': plc_config.PlacePhone, # p7
    'CT47-ML-RS-03': plc_config.PlaceInstruction, # p5

    'test1': plc_config.PlaceChDQ, # p4
    # 'test2': plc_config.PlaceBat, # p2
    '50183411-001': plc_config.PlaceStrap, # p6
    # 'EULA-EN-IN-O1': plc_config.PlaceLicence, # p5
    'EULA-EN-IN-01 Rev A': plc_config.PlaceLicence, # p5
    'test5': plc_config.PlaceBat # p2
}
#
# main_config = { # pn: plc_address
#     plc_config.PlaceCable:['CBL-500-120-S00-05',], # shu ju xian p3
#     # 'CT47-X1N-37D1E0G': plc_config.PlacePhone, # p7
#     # 'CT47-X1N-38D1E0G': plc_config.PlacePhone, # p7
#     plc_config.PlaceInstruction:['CT47-ML-RS-03'], # p5
#
#     plc_config.PlaceChDQ: ['test1'], # p4
#     plc_config.PlaceBat: ['test2'], # p2
#     plc_config.PlaceStrap:['50183411-001'], # p6
#     plc_config.PlaceLicence:['test4'], # p5
#     plc_config.PlaceBat:['test5']
# }


lock_plc = threading.Lock()

class Main:

    def __init__(self):
        # # plc handle
        # lock_plc.acquire()
        # self.plc_main_handle = HuoniPlcScanClientBase(plc_config.PlacePhone)
        # lock_plc.release()
        # self.plc_handle.connect()
        # mess handle
        self.mess_handle = HuoniMessClient()
        # printer handle
        self.printer_handle = HoneyPrintClient()
        self.pool = BoundThreadPoolExecutor(qsize=18, max_workers=18)
        self.sku = 'CT47-X1N-38D1E0G'
        # self.sku = 'CT45P-X0N-37D103G'
        # self.sku = 'CT45P-X0N*'
        self.debug = 1

    def main(self, isUi=False):
        try:
            # # 1 connection
            # print('\n\n1 connection ')
            # hm = HuoniMessClient()
            # # hm.connect()

            # # 2 getting user
            # print('\n\n2 getting user')
            # username = 'e587996'
            # res_user = self.mess_handle.getKitUserByName(username) # Kitting_User
            # print('user...')
            # print(res_user)

            # 3 getting product
            print('\n\n3 getting product')
            # sku = 'CT47-X1N-37D1E0G'
            # sku = 'CT47-X1N-38D1E0G'
            rows = self.mess_handle.getBzBySku(sku=self.sku)  # 拉 Kitting_newunittype
            print(f'product information...')
            for k, v in rows[0].items():
                print(f'{k}: {v}')
            res_pd = rows[0]
            #
            if res_pd['F_NeedCheckQCDCS']==1:
                # 需要查询MDCS中的表tblitems?
                pass

            if res_pd['F_NeedKitLabel'] == 1: # 是否需要打印Kit标签
                pass

            if res_pd['F_BlockStatus'] == 1:
                # 表示这个SKU是否允许包装
                # =1表示 不可以包装，需要提醒 这个产品因为质量或者其他问题，暂时不可以包装出货
                # =0表示可以包装

                pass

            # 4 FAI and compare
            print('\n\n4 get FAI and compare')
            if not self.debug:
                res_fai = self.mess_handle.getFAIByUnitType(unit_type=res_pd['F_Unit_type']) # Kitting_FAIContains \
                for res in res_fai:
                    print(res)
                    # for k,v in res.items():
                    #     print(f'{k}: {v}')
                    if res['FAIStatus'] == 1: #
                        # 表示需要做FAI检查，输入并比较确认具体的物料的料号是否正确 todo
                        bom_item_pn = res['f_items']
                        # if bom_item_pn!='CT47-ML-RS-03':
                        #     continue
                        # plc_work_thread(addressTable=main_config[bom_item_pn], mess_res=bom_item_pn)
                        self.pool.submit(compare_scan_work_thread, addressTable=main_config[bom_item_pn], mess_res=bom_item_pn)  #
                        pass
                    if res['KeyPartNeedScanSN'] == 1: #
                        # 需要输入具体的SN
                        pass
            else:
                # debug
                for k,v in main_config.items():
                    # self.pool.submit(plc_work_thread, addressTable=main_config[k], mess_res=k)
                    self.pool.submit(compare_scan_work_thread, addressTable=main_config[k], mess_res=k)


            # 5 which to upload
            print('\n\n5 which to upload')
            res_itemsUpload = self.mess_handle.getItemsUpload(unit_type=res_pd['F_Unit_type'])  # Kitting_FAIContains  [{},{}]
            print(f'res_itemsUpload {res_itemsUpload}') # decode todo
            if len(res_itemsUpload)==0:
                # nothing to upload
                pass
            else:
                for res in res_itemsUpload:
                    # res['F_Items']  this to upload todo
                    pass

            '''
            bellow is for each serial number
            '''
            self.pool.submit(phone_work_thread, self.mess_handle, part_number=self.sku)
            self.pool.submit(print_work_thread, self.mess_handle, self.printer_handle, res_pd, part_number=self.sku)

            # phone_work_thread(self.mess_handle, part_number=self.sku)
            # print_work_thread(self.mess_handle, self.printer_handle, res_pd, part_number=self.sku)

            if isUi:
                return
            while True:
                time.sleep(1000000)
            # self.mess_handle.close()

        except Exception as e:
            logger.error(f'main: {e}')
            logger.error(traceback.format_exc())

def phone_work_thread(mess_handle, part_number = ''):
    '''
        bellow is for each serial number
        get sn; is pass;
    :return:
    '''
    try:
        lock_plc.acquire()
        plc_phone_handle = HuoniPlcScanClientBase(plc_config.PlacePhone)
        lock_plc.release()
        device_name = '点位7手机'
        while True:

            # 1 judge is check by product from mess
            print(f'{device_name} 1 judge is check by product from mess')
            isCheck = 1  # get isCheck from mess, 1 ture 2 false todo
            plc_phone_handle.set_is_need_check(isCheck)  #
            print(f'{device_name} isCheck {isCheck}')
            if not isCheck:
                return

            #  todo
            # print(f'\n\n 5 get serial number and pn from plc')
            # self.plc_main_handle = HuoniPlcScanClientBase(plc_config.PlacePhone)
            print(f'{device_name} 2 wait scan done')
            # isDone = 0  # 1 ture 2 false
            # while isDone == 0:
            #     isDone = self.plc_main_handle.get_is_scan_done()
            #     time.sleep(0.1)  # s
            # self.plc_main_handle.set_zero_is_scan_done()  # to 0
            # print(f'{device_name} isDone {isDone}')
            plc_phone_handle.wait_plc(plc_phone_handle.get_is_scan_done,plc_phone_handle.set_zero_is_scan_done)

            print(f'{device_name} 3 get scan res and check by mess')
            sn_scan_res = plc_phone_handle.get_scan_res()
            # mess_res = '12345678'  # get code from mess todo
            print(f'{device_name} sn_scan_res {sn_scan_res}')
            # if len(sn_scan_res) == 0:


            serial_number = sn_scan_res
            part_number = part_number
            # serial_number = '22306B13A3'
            # part_number = 'CT47-X1N-38D1E0G'
            # 6 is pass from QCDCS
            print(f'{device_name} 4 is pass from QCDCS')  #
            res_isPass = mess_handle.getIsPassFromQCDCS(serial=serial_number)  # tblItems  qcdcs??   [{},{}]
            # res_isPass = res_isPass[0]
            # post_status = res_isPassQCDCS[0]['post_status'] # "2"表示可以包装
            # isPass = len(sn_scan_res) > 0 and len(res_isPass) > 0 and res_isPass[0]['post_status'] == 2 and res_isPass[0]['model'] == res_isPass[0][
            #     'BF_Model']
            isPass = len(sn_scan_res) > 0 # not care mess
            print(F'res_isPass {res_isPass}')
            print(f'{device_name} isPass {isPass}')
            # if not isPass and False:
            if not isPass:
                # to plc ng
                plc_phone_handle.set_check_res(2) # check ng
                # break
            else:
                plc_phone_handle.set_check_res(1)  # check ok
            pass
    except Exception as e:
        logger.error(f'{device_name} {e}')
        logger.error(traceback.format_exc())


def print_work_thread(mess_handle, printer_handle, res_pd, part_number):
    '''
    wait, print label, isDone

    :param mess_handle:
    :param printer_handle:
    :param res_pd:
    :param part_number:
    :return:
    '''
    try:

        thread_name = '打印机线程'
        plc_print_handle = HuoniPlcScanClientBase(plc_config.PlacePhone)

        while True:
            # 1  wait
            print(f'\n\n{thread_name} 1 wait for plc to print')
            plc_print_handle.wait_plc(plc_print_handle.get_is_print_chufa,
                                          plc_print_handle.set_zero_is_print_chufa)  # wait
            # serial_number = plc_print_handle.get_scan_res() # use new var todo
            serial_number = plc_print_handle.get_serial_number()
            print(f'{thread_name} gotten serial_number {serial_number}')

            # 2 get Label Name and label content from mess, then print
            print(f'{thread_name} 2 get Label Name and label content')  # need pn, sn
            res_labelNames = mess_handle.getLabelName(F_Unit_type=res_pd['F_Unit_type'],
                                                           F_LabelGroupName='KitLabel')  # [{},{}] ones
            print(res_labelNames)
            # F_LabelName = res_labelNames[0]['F_LabelName'] #
            for res in res_labelNames:  # maybe muti labels, now ones
                # get label content
                F_LabelName = res['F_LabelName']
                res_labelContents = mess_handle.getLabelContent(F_LabelName=F_LabelName,
                                                                     F_Unit_type=res_pd['F_Unit_type'])  # [{},{}]
                print(res_labelContents)
                # get print value from qcdcs
                res_labelvars = mess_handle.getLabelVarFromQCDCS(pn=part_number, sn=serial_number)
                print(f'{thread_name} res_labelvars {res_labelvars}')  # bda, imei, imei2, meid, meid2, wifi
                for res_labelContent in res_labelContents:
                    if res_labelContent['F_MDCSVariable']:  # is get value from cdcs
                        # value = 'getFromCdcs' # # get from cdcs todo
                        b = res_labelContent['F_MDCSVariableName']
                        for res_labelvar in res_labelvars:  # loop twice
                            a = res_labelvar['Type']
                            if a == b:
                                print(f"{res_labelvar['Type']}  {res_labelvar['Value']}")
                                # value = res_labelvar['Value']
                                res_labelContent['F_VariableValue'] = res_labelvar['Value']
                                break
                res_labelContents.append({'F_VariableName': 'ITEM', 'F_VariableValue': part_number})
                res_labelContents.append({'F_VariableName': 'DSN', 'F_VariableValue': serial_number})

                # control printer to print label
                pof_path = f'./printer/pof/{F_LabelName}'  # \\ch3uw1050\THLabel\Barone\POF\
                printer_handle.printOneLabel(res_labelContents, template_path=pof_path)
                # to plc, print done
                plc_print_handle.set_is_print_done(1)  # 1  print done
                print(f'{thread_name} print done')
                # plc_print_handle.set_check_res(1)
            # 8 如果需要做关键物料的SN追溯，需要把数据保存到这个表
            pass
    except Exception as e:
        logger.error(e)
        logger.error(traceback.format_exc())
        printer_handle.close()
    finally:
        if printer_handle is not None:
            printer_handle.close()


def compare_scan_work_thread(addressTable=plc_config.PlaceBat, mess_res='12345678'):
    '''
    for comparing scan result with mess
    :param addressTable:
    :param mess_res:
    :return:
    '''
    try:
        device_name = addressTable['device_name']
        lock_plc.acquire()
        plc_handle = HuoniPlcScanClientBase(addressTable)
        lock_plc.release()

        # print(f'xxxxxx {addressTable}')
        while 1:
            # plc_handle.set_addressTable(addressTable) #
            # hn_plc = HuoniPlcScanClientBase(addressTable=config.PlaceBat)
            # self.connect()

            # 1 judge is check by product from mess
            print(f'{device_name} 1 judge is check by product from mess')
            isCheck = 1  # get isCheck from mess, 1 ture 2 false todo
            plc_handle.set_is_need_check(isCheck)  #
            print(f'{device_name} isCheck {isCheck}')
            if not isCheck:
                return

            # 2 wait scan done
            print(f'{device_name} 2 wait scan done')
            isDone = 0  # 1 ture 2 false
            while isDone == 0:
                isDone = plc_handle.get_is_scan_done()
                time.sleep(0.1)  # s
            plc_handle.set_zero_is_scan_done()  # to 0
            print(f'{device_name} isDone {isDone}')

            # 3 get scan res and check by mess
            print(f'{device_name} 3 get scan res and check by mess')
            scan_res = plc_handle.get_scan_res()
            # mess_res = '12345678'  # get code from mess todo
            print(f'{device_name} scan_res {scan_res}')
            print(f'{device_name} mess_res {mess_res}')
            isRight = 2  # 1 ture 2 false
            if scan_res == mess_res or (mess_res == 'test5' and len(scan_res)>0): # now bat is always ok
                isRight = 1
            # isRight = 1 # always true

            # 4 return isRight to plc
            print(f'{device_name} 4 return isRight to plc')
            plc_handle.set_check_res(isRight)
            print(f'{device_name} isRight {isRight}')

            # hn_plc.set_scan_res('!123qwer12fsfder3')
            # value = hn_plc.get_scan_res()
            # print(value)

            # self.close()
    except Exception as e:
        logger.error(f'{device_name} {e}')
        logger.error(traceback.format_exc())



if __name__ =='__main__':
    # test_HuoniMessClient()
    Main().main()